﻿using SCG.SolarVengeanceEngine;
using SCG.SolarVengeanceEngine.BrainInfo;
using System;
using System.Collections.Generic;

namespace SCG.SolarVengeance.Brains
{
    public class Maximizar : Brain
    {
        //challenge level
        public override ChallengeLevel Challenge
        {
            get
            {
                return ChallengeLevel.Easy;
            }
        }

        //which starships?
        public override List<StarShipType> AvailableShipTypes
        {
            get
            {
                List<StarShipType> lst = new List<StarShipType>();
                lst.Add(StarShipType.WarShip);
                lst.Add(StarShipType.Zealot);
                lst.Add(StarShipType.Freighter);
                lst.Add(StarShipType.InkSpot);
                lst.Add(StarShipType.Refinery);
                lst.Add(StarShipType.Drone);
                return lst;
            }
        }

        //brain logic
        public override void Execute()
        {
            //count my starsystems
            List<StarSystemInfo> mySystems = new List<StarSystemInfo>();
            foreach(StarSystemInfo sys in StarSystems)
            {
                sys.BrainData = 0;
                if (sys.OwnedByMe)
                    mySystems.Add(sys);
            }

            //initialize null objects
            foreach (StarShipInfo ship in MyStarShips)
                if (ship.BrainData == null)
                    ship.BrainData = 0;
    
            //count starships
            int numZ = 0;
            int numRF = 0;
            foreach(StarShipInfo ship in MyStarShips)
            {
                if (ship.ShipType == StarShipType.Refinery)
                    numRF++;
                else if (ship.ShipType == StarShipType.Zealot)
                    numZ++;
        
                //it it defending a starsystem?
                if (ship.ShipType == StarShipType.WarShip)
                    if ((int)ship.BrainData == 2)
                    {
                        StarSystemInfo sys = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Owned);
                        if (sys != null)
                            sys.BrainData = 1;
                    }
            }
    
            //process my starsystems
            foreach(StarSystemInfo sys in mySystems)
            {
                //defense code
                StarShipInfo enemy = ClosestStarShip(sys.X, sys.Y, 10, FindShipFlags.Enemy, ShipKnownFlags.Either);
                if (enemy != null)
                {
                    if (sys.Shields < sys.Value * 0.4)
                        BuildShields(sys, 1);
                    for(int n = 0; n < Random(2, 5); n++)
                        BuildStarShip(sys, StarShipType.Drone, Random(2, 5), 0, false);
                }
        
                //should it have a refinery?
                if (sys.Value > 15)
                {
                    //does it have a refinery?
                    StarShipInfo refinery = null;
                    bool hasRefinery = false;
                    foreach(StarShipInfo ship in MyStarShips)
                        if (ship.IsAdjacentTo(sys))
                            if (ship.ShipType == StarShipType.Refinery)
                            {
                                refinery = ship;
                                hasRefinery = true;
                                break;
                            }
            
                    //build a refinery
                    if (!hasRefinery)
                    {
                        BuildStarShip(sys, StarShipType.Refinery, 6, 0, false);
                    }
                    else
                    {
                        //does the refinery have a freighter?
                        bool hasFreighter = false;
                        foreach(StarShipInfo ship in MyStarShips)
                            if (ship.IsAdjacentTo(refinery) || ship.IsAdjacentTo(sys))
                                if (ship.ShipType == StarShipType.Freighter)
                                {
                                    hasFreighter = true;
                                    break;
                                }
                
                        //build a freighter
                        if (!hasFreighter)
                        {
                            BuildStarShip(sys, StarShipType.Freighter, 4, 4, false);
                        }
                    }
                }
                else
                {
                    BuildStarShip(sys, StarShipType.WarShip, Random(5, 20), Random(3, 10), false);
            
                    //build a zealot?
                    if (numZ < mySystems.Count / 10 + 1)
                        BuildStarShip(sys, StarShipType.Zealot, Random(8, 12), Random(6, 10), true);
                }
            }
    
            //process starships
            List<StarSystemInfo> zealotSystems = new List<StarSystemInfo>();
            foreach(StarShipInfo ship in MyStarShips)
            {
                switch (ship.ShipType)
                {
                    case StarShipType.Refinery:
                    {
                        //build a zealot?
                        if (numZ < mySystems.Count / 10 + 1)
                        {
                            StarSystemInfo sys = ClosestStarSystem(ship.X, ship.Y, 5, FindSystemFlags.Owned);
                            if (sys != null)
                                if ((int)sys.BrainData == 1)
                                    BuildStarShip(sys, StarShipType.Zealot, Random(8, 12), Random(6, 10), true);
                        }
                
                        int value = 30;
                        int engines = 20;
                        for(int n = 0; n < 4; n ++)
                        {
                            int v = (int)(value * SVGame.RNG.NextDouble());
                            if (v < 3)
                                v = 3;
                            int e = engines + Random(-3, 3);
                            if (e < 5)
                                e = 5;
                            if (e > 20)
                                e = 20;
                            BuildStarShip(ship, StarShipType.WarShip, e, v, false);
                            value -= 4;
                            engines -= 3;
                        }
                        break;
                    }
                    case StarShipType.WarShip:
                    {
                        if ((int)ship.BrainData == 0)
                        {
                            ship.BrainData = 1;
                            if (ship.Value > 6)
                            {
                                StarSystemInfo sys = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Owned);
                                if (sys.Value > 12)
                                    ship.BrainData = (int)sys.BrainData == 0 ? 2 : 1;
                                else
                                    ship.BrainData = 1;
                            }
                        }
                        switch ((int)ship.BrainData)
                        {
                            case 1:
                            {
                                StarSystemInfo sys = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Unfriendly);
                                if (sys != null)
                                {
                                    Target(ship, sys);
                                    AttackAdjacent(ship, !ship.IsAdjacentTo(sys));
                                }
                                break;
                            }
                            case 2:
                            {
                                StarSystemInfo sys = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Owned);
                                if (sys != null)
                                {
                                    Defend(ship, sys);
                                }
                                break;
                            }
                        }
                        break;
                    }
                    case StarShipType.Drone:
                    {
                        StarSystemInfo sys = ClosestStarSystem(ship.X, ship.Y, Int32.MaxValue, FindSystemFlags.Owned);
                        if (sys != null)
                        {
                            if (ship.IsAdjacentTo(sys))
                                Move(ship, ship.X + Random(-5, 5), ship.Y + Random(-5, 5));
                            else
                                Defend(ship, sys);
                        }
                        break;
                    }
                    case StarShipType.Freighter:
                    {
                        if (ship.Order == OrderType.None)
                        {
                            StarSystemInfo sys = ClosestStarSystem(ship.X, ship.Y, 3, FindSystemFlags.Owned);
                            if (sys != null)
                            {
                                foreach(StarShipInfo refinery in MyStarShips)
                                    if (refinery.ShipType == StarShipType.Refinery)
                                        if (refinery.IsAdjacentTo(sys))
                                        {
                                            ship.BrainData = 1;
                                            List<SVObjectInfo> sources = new List<SVObjectInfo>();
                                            sources.Add(sys);
                                            Transport2(ship, sources, refinery);
                                            break;
                                        }
                            }
                        }
                        break;
                    }
                    case StarShipType.Zealot:
                    {
                        int dist = Int32.MaxValue;
                        StarSystemInfo targ = null;
                        foreach(StarSystemInfo sys in StarSystems)
                            if (!sys.OwnedByMe)
                                if (!zealotSystems.Contains(sys))
                                {
                                    int d = (int)Distance(ship.X, ship.Y, sys.X, sys.Y);
                                    if (d < dist)
                                    {
                                        dist = d;
                                        targ = sys;
                                    }
                                }
                        if (targ != null)
                        {
                            if (Distance(ship.X, ship.Y, targ.X, targ.Y) >= ship.Value)
                                Move(ship, targ.X, targ.Y);
                            else
                                ClearOrder(ship);
                            zealotSystems.Add(targ);
                        }
                        break;
                    }
                }
            }
        }

        //description
        public override string Description
        {
            get
            {
                return "Uses Refineries to boost production, and some unconventional tactics to conquer StarSystems.";
            }
        }
    }
}
